//
//  SqfliteSqlCipherTool.m
//  sqflite_sqlcipher
//
//  Created by zhong on 2021/12/16.
//

#import "SqfliteSqlCipherTool.h"
#import <sqlite3.h>

@implementation SqfliteSqlCipherTool

+ (BOOL)has_key:(NSString *)path {
    BOOL res = NO;
    NSData *data = [NSData dataWithContentsOfFile:path];
    if (data.length >= 16) {
        NSData *headData = [data subdataWithRange:NSMakeRange(0, 16)];
        NSString *string = [[NSString alloc] initWithData:headData encoding:NSASCIIStringEncoding];
        res = ![string containsString:@"SQLite format 3"];
    }
    return res;
}

+ (BOOL)encrypt_db:(NSString *)path password:(NSString *)password {
    return [self change_encrypted_db:path old_password:@"" new_password:password];
}

+ (BOOL)un_encrypted_db:(NSString *)path password:(NSString *)password {
    return [self change_encrypted_db:path old_password:password new_password:@""];
}

+ (BOOL)change_encrypted_db:(NSString *)path old_password:(NSString *)old_password new_password:(NSString *)new_password {
    NSFileManager *fm = [[NSFileManager alloc] init];
    BOOL result = NO;
    if (![fm fileExistsAtPath:path]) {
        return result;
    }
    NSString *temp_path = [NSString stringWithFormat:@"%@.temp1.db", path];
    sqlite3 *db;
    @try {
        char *msg;
        if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
            if (old_password.length > 0) {
                const char *old_key = [[NSString stringWithFormat:@"PRAGMA key = '%@'", old_password] UTF8String];
                sqlite3_exec(db, old_key, NULL, NULL, &msg);
            }
            const char *new_key = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS encrypted KEY '%@'", temp_path, new_password ?: @""] UTF8String];
            sqlite3_exec(db, new_key, NULL, NULL, &msg);
            if (msg == NULL) {
                sqlite3_exec(db, "begin exclusive transaction", NULL, NULL, &msg);
                sqlite3_exec(db, "SELECT sqlcipher_export('encrypted');", NULL, NULL, &msg);
                sqlite3_exec(db, "commit transaction", NULL, NULL, &msg);
                sqlite3_exec(db, "DETACH DATABASE encrypted;", NULL, NULL, &msg);
                result = (msg == NULL);
            } else {
                result = NO;
            }
        }
    } @catch (NSException *exception) {
        result = NO;
    } @finally {
        if (result) {
            NSError *error;
            NSString *temp_path_2 = [NSString stringWithFormat:@"%@.temp.db", path];
            [fm moveItemAtPath:path toPath:temp_path_2 error:&error];
            [fm moveItemAtPath:temp_path toPath:path error:&error];
            if (error) {
                [fm moveItemAtPath:temp_path_2 toPath:path error:&error];
                result = NO;
            } else {
                [fm removeItemAtPath:temp_path_2 error:&error];
            }
        }
        if ([fm fileExistsAtPath:temp_path]) {
            [fm removeItemAtPath:temp_path error:nil];
        }
        sqlite3_close(db);
    }
    return result;
}

@end
